#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

namespace GlibcModule
{

#define MAX 1024
#define NONE_FFLUSH (1 << 0)
#define LINE_FFLUSH (1 << 1)
#define FULL_FFLUSH (1 << 2)

    class MyFile
    {
    public:
        MyFile(int fd, int flag)
            : _fileno(fd), _flag(flag), _buffer_len(0), _fflush_mode(LINE_FFLUSH)
        {
            memset(_outbuffer, 0, sizeof(_outbuffer));
        }

        MyFile *MyFopen(const char *path, const char *mode)
        {
            int fd = -1;
            int flag = 0;

            if (strcmp(mode, "r") == 0)
            {
                flag = O_RDONLY;
                fd = open(path, flag, 0666);
            }
            else if (strcmp(mode, "w") == 0)
            {
                flag = O_WRONLY | O_CREAT | O_TRUNC;
                fd = open(path, flag, 0666);
            }
            else if (strcmp(mode, "a") == 0)
            {
                flag = O_WRONLY | O_CREAT | O_APPEND;
                fd = open(path, flag, 0666);
            }
            else
            {
                // TODO
            }

            if (fd < 0)
                return nullptr;

            return new MyFile(fd, flag);
        }

        void MyFclose(MyFile *file)
        {
            if (file->_buffer_len < 0)
                return;

            MyFflush(file);
            close(file->_fileno);
            delete file;
        }

        int MyFwrite(MyFile *file, void *str, int len)
        {
            memcpy(file->_outbuffer + file->_buffer_len, str, len);
            file->_buffer_len += len;

            if ((file->_fflush_mode & LINE_FFLUSH) && file->_outbuffer[file->_buffer_len - 1] == '\n')
            {
                MyFflush(file);
            }

            return 0;
        }

        void MyFflush(MyFile *file)
        {
            if (file->_buffer_len <= 0)
                return;

            write(file->_fileno, file->_outbuffer, file->_buffer_len);//将用户缓冲区的内容用系统调用打到内核缓冲区中
            fsync(file->_fileno);//将内核缓冲区的内容同步到磁盘
            file->_buffer_len = 0;
        }

        ~MyFile()
        {
        }

        const char *GetOutBuffer()
        {
            return _outbuffer;
        }

    private:
        int _fileno;
        int _flag;
        char _outbuffer[MAX];
        int _buffer_len;
        int _fflush_mode;
    };
}